﻿using System;
using System.Text;
using System.Reflection;
using System.Collections.Generic;
using Ex03.GarageLogic;

namespace Ex03.GarageManagementSystem.ConsoleUI
{
    public static class MenuGenerator
    {
        public enum eMenuOptions
        {
            [StringValue("Insert Vehicle To Garage")]
            InsertVehicleToGarage = 1,
            [StringValue("Show Vehicles In Garage")]
            ShowVehiclesInGarage,
            [StringValue("Show Vehicles In Garage (With status filter")]
            ShowVehiclesInGarageByStatus,
            [StringValue("Change Vehicle Status In Garage")]
            ChangeVehicleStatusInGarage,
            [StringValue("Fully Inflate Vehicle Wheels")]
            FullyInflateVehicleWheels,
            [StringValue("Refuel Vehicle (Fuel powered vehicles only)")]
            RefuelVehicle,
            [StringValue("Charge Vehicle (Electric powered vehicles only)")]
            ChargeVehicle,
            [StringValue("ShowVehicleDetails")]
            ShowVehicleDetails,
            [StringValue("Exit system")]
            Exit
        }

        private const string k_MainMenuGreeting = "Welcome to the garage managment system";
        private const string k_MainMenuTitle = "Main Menu";
        private const bool k_ParsedOK = true;

        /// <summary>
        /// Presents the main menu of the garage managment system and lets the user choose from
        /// a list of available actions
        /// </summary>
        /// <returns> Enum representing the action the user chose</returns>
        public static eMenuOptions PresentMainMenuAndGetUserChoice()
        {
            int optionChosen;
            bool parseStatus;
            eMenuOptions OptionTypeChosen;
            StringBuilder stringBuilder;
            ScreenCleaner screenCleaner = new ScreenCleaner();
            int numberOfMenuOptions = Enum.GetValues(typeof(eMenuOptions)).Length;

            do
            {
                parseStatus = k_ParsedOK;
                screenCleaner.Clear();
                stringBuilder = new StringBuilder();
                stringBuilder.AppendFormat("================= {0} =================", k_MainMenuTitle);
                stringBuilder.AppendLine();
                stringBuilder.AppendLine();
                stringBuilder.Append(getMainMenuOptionsString());
                stringBuilder.AppendLine();
                stringBuilder.Append("=============================================");
                stringBuilder.AppendLine();
                stringBuilder.Append("Enter your choice: ");
                Console.Write(stringBuilder.ToString());
                parseStatus = int.TryParse(Console.ReadLine(), out optionChosen);
                Console.WriteLine("=============================================");
            } while ((parseStatus == !k_ParsedOK) || (optionChosen < 1) || (optionChosen > numberOfMenuOptions));

            OptionTypeChosen = (eMenuOptions)Enum.Parse(typeof(eMenuOptions), optionChosen.ToString());

            return OptionTypeChosen;
        }

        private static string getMainMenuOptionsString()
        {
            StringBuilder stringBuilder = new StringBuilder();
            int numberOfMenuOptions = Enum.GetValues(typeof(eMenuOptions)).Length;
            List<string> menuOptionsList = getMainMenuOptionsStrings();

            foreach (eMenuOptions menuOption in Enum.GetValues(typeof(eMenuOptions)))
            {
                stringBuilder.AppendFormat("{0}. {1}", ((int)menuOption), menuOptionsList[(int)menuOption - 1]);
                stringBuilder.AppendLine();
            }

            return stringBuilder.ToString();
        }

        public static VehiclesConstructor.eVehicleTypeSupported PresentVehicleTypeMenuAndGetUserChoice()
        {
            int optionChosen;
            bool parseStatus;
            VehiclesConstructor.eVehicleTypeSupported typeChosen;
            int numberOfVehicleOptions = Enum.GetValues(typeof(VehiclesConstructor.eVehicleTypeSupported)).Length;

            do
            {
                Console.WriteLine("Choose your vehicle type");

                for (int i = 1; i <= numberOfVehicleOptions; ++i)
                {
                    Console.WriteLine(string.Format("{0}. {1}", i, VehiclesConstructor.Instance.SupportedTypes[i - 1]));
                }

                Console.Write(string.Format("Enter your choice ({0}-{1}): ", 1, numberOfVehicleOptions));
                parseStatus = int.TryParse(Console.ReadLine(), out optionChosen);
            } while ((parseStatus == !k_ParsedOK) || (optionChosen < 1) || (optionChosen > numberOfVehicleOptions));

            return typeChosen = (VehiclesConstructor.eVehicleTypeSupported)Enum.Parse(typeof(VehiclesConstructor.eVehicleTypeSupported), optionChosen.ToString());
        }

        public static GarageClient.eProcessStatus PresentProcessStatusMenuAndGetUserChoice(string i_MenuTitle)
        {
            int optionChosen;
            bool parseStatus;
            GarageClient.eProcessStatus statusChosen;
            int numberOfProcessStatusOptions = Enum.GetValues(typeof(GarageClient.eProcessStatus)).Length;

            do
            {
                Console.WriteLine(i_MenuTitle);
                foreach (GarageClient.eProcessStatus StatusType in Enum.GetValues(typeof(GarageClient.eProcessStatus)))
                {
                    Console.WriteLine(string.Format("{0}. {1}", ((int)StatusType), Enum.GetName(typeof(GarageClient.eProcessStatus), (int)StatusType)));
                }

                Console.Write(string.Format("Enter your choice ({0}-{1}): ", 1, numberOfProcessStatusOptions));
                parseStatus = int.TryParse(Console.ReadLine(), out optionChosen);
            } while ((parseStatus == !k_ParsedOK) || (optionChosen < 1) || (optionChosen > numberOfProcessStatusOptions));

            Console.WriteLine();

            return statusChosen = (GarageClient.eProcessStatus) Enum.Parse(typeof(GarageClient.eProcessStatus), optionChosen.ToString());
        }

        /// <summary>
        /// This function presents all fuel types of vehicles and lets the user choose
        /// which fuel type he wants from the list.
        /// </summary>
        /// <returns> An enum representing the fuel type the user selected</returns>
        public static FuelPoweredVehicle.eFuelType PresentFuelTypeMenuAndGetUserChoice()
        {
            int optionChosen;
            bool parseStatus;
            FuelPoweredVehicle.eFuelType fuelChosen;
            int numberOfFuelOptions = Enum.GetValues(typeof(GarageClient.eProcessStatus)).Length;

            do
            {
                Console.WriteLine("Choose fuel type");
                foreach (FuelPoweredVehicle.eFuelType StatusType in Enum.GetValues(typeof(FuelPoweredVehicle.eFuelType)))
                {
                    Console.WriteLine(string.Format("{0}. {1}", ((int)StatusType), Enum.GetName(typeof(FuelPoweredVehicle.eFuelType), (int)StatusType)));
                }

                Console.Write(string.Format("Enter your choice ({0}-{1}): ", 1, numberOfFuelOptions));
                parseStatus = int.TryParse(Console.ReadLine(), out optionChosen);
            } while ((parseStatus == !k_ParsedOK) || (optionChosen < 1) || (optionChosen > numberOfFuelOptions));

            Console.WriteLine();

            return fuelChosen = (FuelPoweredVehicle.eFuelType)Enum.Parse(typeof(FuelPoweredVehicle.eFuelType), optionChosen.ToString());
        }

        /// <summary>
        /// This function presents all plate numbers of vehicles in garage and lets the user choose
        /// which vehicle he wants from the list. 
        /// </summary>
        /// <param name="i_VehiclesPlateNumber"></param>
        /// <returns> A string representing the plate number of the chosen vehicle </returns>
        public static string PresentVehiclesPlateNumberAndGetUserChoice(List<string> i_VehiclesPlateNumber)
        {
            bool parseStatus;
            int optionChosen;
            int numberOfOptions = i_VehiclesPlateNumber.Count;

            do
            {
                Console.WriteLine("Choose vehicle for operation");
                for (int i = 1; i <= numberOfOptions; ++i)
                {
                    Console.WriteLine(string.Format("{0}. {1}", i, i_VehiclesPlateNumber[i - 1]));
                }

                Console.Write(string.Format("Enter your choice ({0}-{1}): ", 1, numberOfOptions));
                parseStatus = int.TryParse(Console.ReadLine(), out optionChosen);
            } while ((parseStatus == !k_ParsedOK) || (optionChosen < 1) || (optionChosen > numberOfOptions));

            Console.WriteLine();

            return i_VehiclesPlateNumber[optionChosen - 1];
        }

        private static List<string> getMainMenuOptionsStrings()
        {
            const bool v_Inherit = true;
            Array menuOptions = System.Enum.GetValues(typeof(eMenuOptions));
            Type type;
            FieldInfo fieldInfo;
            StringValue[] attrArray;
            List<string> menuOptionStrings = new List<string>();

            foreach (eMenuOptions option in menuOptions)
            {
                type = option.GetType();
                fieldInfo = type.GetField(option.ToString());
                attrArray = fieldInfo.GetCustomAttributes(typeof(StringValue), !v_Inherit) as StringValue[];

                foreach (StringValue attr in attrArray)
                {
                    menuOptionStrings.Add(attr.Value);
                }
            }

            return menuOptionStrings;
        }
    }
}
